/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package binh;

import we.dispatcher.CPacketWriter;

/**
 *
 * @author ADMIN
 */
public class CTable implements ILoopable
{

    private int index;
    public CChannel Channel;
    public CClient[] ClientList;
    public CClient Owner;
    public int TableId;
    public int MaxGameClient;
    public int GameStage;
    public int TimeStage;
    public CClient Turn;
    public int TimeTurn;
    public int TimeGame;
    public double GoldBet;
    public CGameLogic GameLogic;
    public int ChickenBet;
    public int NumChicken;
    public int MaxClient;
    int GameId;

    public CTable(int index, CChannel Channel)
    {
        MaxClient = CConfig.MaxClientInTable;
        ClientList = new CClient[CConfig.MaxClient];
        this.index = index;
        this.Channel = Channel;
        Owner = null;
        Turn = null;
        ChickenBet = 0;
        NumChicken = 0;
    }

    public void SetMaxClient(int MaxClient)
    {
        this.MaxClient = MaxClient;
        ClientList = new CClient[MaxClient];
    }

    public int GetIndex()
    {
        return index;
    }

    public void Destroy()
    {
        ChickenBet = 0;
        NumChicken = 0;
        GameStage = CCommon.GS_WAITING_ROOM;
        Owner = null;
        Turn = null;
    }

    // Remove Client
    public void RemoveClient(CClient Client)
    {
        if (Owner == Client && GetNumPlayer() > 1)
        {
            SetOwner(GetNextClient(Client));
            if (Owner != null)
            {
                CPacketWriter p = new CPacketWriter();
                p.PutID(CCommon.MT_SET_HOST);
                p.PutInt(Owner.GetClientIndex());
                p.PutLengthAndFlip();
                SendExcept(p, Client.GetClientIndex());
            }
        }

        // Update Score
        if (IsPlaying() && Client.IsPlayer())
        {
            GameLogic.OnClientExit(Client);
        }

        // Remove Client
        for (int i = 0; i < MaxClient; i++)
        {
            if (ClientList[i] != null && ClientList[i].GetClientIndex() == Client.GetClientIndex())
            {
                ClientList[i] = null;
                break;
            }
        }

        // Xóa game khi hết người chơi
        if (GetNumPlayer() == 0)
        {
            Destroy();
        }

        // Set Turn
        if (!IsPlaying())
        {
            Turn = Owner;
        }
    }

    public double GetMinGoldBet()
    {
        if (Channel != null)
        {
            return Channel.MinGoldBet;
        }

        return 0;
    }

    // Create Game
    public void CreateGame(double GoldBet)
    {
        this.GameStage = CCommon.GS_WAITING_ROOM;
        //this.GoldBet = GoldBet;
        this.ChickenBet = 0;
        this.NumChicken = 0;
        for (int i = 0; i < MaxClient; i++)
        {
            ClientList[i] = null;
        }
    }

    // Trùng IP
    public boolean CheckSameIP(CClient c)
    {
        if (CConfig.EnableSameIP)
        {
            return false;
        }

        for (int i = 0; i < MaxClient; i++)
        {
            CClient Client = ClientList[i];
            if (Client != null && Client.IsLogin() && !Client.IsBot)
            {
                if (c.GetIP() != "" && c.GetIP().equals(Client.GetIP()))
                {
                    return true;
                }
            }
        }

        return false;
    }

    // Check Add Client
    public boolean CanAddClient(CClient c)
    {
        return (GetNumClient() < MaxClient);
    }

    // Add Client, return Chair
    public int AddClient(CClient Client)
    {
        int Chair = -1;

        if (GetNumClient() == 1)
        {
            if (MaxClient == 2)
            {
                for (int i = 0; i < MaxClient; i++)
                {
                    if (ClientList[i] != null)
                    {
                        Chair = 0;
                        if (i == 0)
                        {
                            Chair = 1;
                        }
                        if (i == 1)
                        {
                            Chair = 0;
                        }
                        ClientList[Chair] = Client;
                        break;
                    }
                }
            } else if (MaxClient == 4)
            {
                for (int i = 0; i < MaxClient; i++)
                {
                    if (ClientList[i] != null)
                    {
                        Chair = 0;
                        if (i == 0)
                        {
                            Chair = 2;
                        }
                        if (i == 1)
                        {
                            Chair = 3;
                        }
                        if (i == 2)
                        {
                            Chair = 0;
                        }
                        if (i == 3)
                        {
                            Chair = 1;
                        }
                        ClientList[Chair] = Client;
                        break;
                    }
                }
            } else if (MaxClient == 6)
            {
                for (int i = 0; i < MaxClient; i++)
                {
                    if (ClientList[i] != null)
                    {
                        Chair = 0;
                        if (i == 0)
                        {
                            Chair = 3;
                        }
                        if (i == 1)
                        {
                            Chair = 4;
                        }
                        if (i == 2)
                        {
                            Chair = 5;
                        }
                        if (i == 3)
                        {
                            Chair = 0;
                        }
                        if (i == 4)
                        {
                            Chair = 1;
                        }
                        if (i == 5)
                        {
                            Chair = 2;
                        }
                        ClientList[Chair] = Client;
                        break;
                    }
                }
            }
        } else
        {
            for (int i = 0; i < MaxClient; i++)
            {
                if (ClientList[i] == null)
                {
                    ClientList[i] = Client;
                    Chair = i;
                    break;
                }
            }
        }

        if (!Client.IsViewer)
        {
            Turn = Owner;
        }

        if (GameStage == CCommon.GS_WAITING_ROOM)
        {
            TimeStage = 5;
        }

        return Chair;
    }

    // Set Owner
    public void SetOwner(CClient Client)
    {
        Owner = Client;
    }

    // Send all
    public void SendAll(CPacketWriter Writer)
    {

        for (int i = 0; i < MaxClient; i++)
        {
            if (ClientList[i] != null && ClientList[i].IsLogin() && !ClientList[i].IsBot)
            {
                ClientList[i].SendDuplicate(Writer);
            }
        }
    }

    // Send Except
    public void SendExcept(CPacketWriter Packet, int ClientId)
    {
        for (int i = 0; i < MaxClient; i++)
        {
            if (ClientList[i] != null
                    && ClientList[i].IsLogin()
                    && !ClientList[i].IsBot
                    && ClientList[i].GetClientIndex() != ClientId)
            {
                ClientList[i].SendDuplicate(Packet);
            }
        }
    }

    // Send Client Join info
    public void SendClientJoin(CClient Client)
    {
        int IsOwner = (Owner == Client) ? 1 : 0;
        int IsViewer = (Client.IsViewer) ? 1 : 0;
        CPacketWriter p1 = new CPacketWriter();
        p1.PutID(CCommon.MT_GAME_CLIENT_JOIN);
        p1.PutInt(Client.GetClientIndex());
        p1.PutInt(Client.AvatarId);
        p1.PutInt(Client.Chair);
        p1.PutInt(IsOwner);
        p1.PutInt(IsViewer);
        p1.PutInt(Client.Level);
        p1.PutDouble(Client.GetGold());
        p1.PutString(Client.Username, CCommon.MAX_USERNAME_LENGTH);
        p1.PutInt(Client.IsChickenBet ? 1 : 0);
        p1.PutString(Client.RealName, CCommon.MAX_USERNAME_LENGTH);
        p1.PutDouble(GoldBet);
        p1.PutLengthAndFlip();
        SendAll(p1);

        if (!Client.IsBot)
        {
            for (int i = 0; i < MaxClient; i++)
            {
                CClient o = ClientList[i];
                if (o != null && o.IsLogin() && o != Client && !o.IsViewer)
                {
                    IsOwner = (o == Owner) ? 1 : 0;
                    IsViewer = (o.IsViewer) ? 1 : 0;

                    CPacketWriter p2 = new CPacketWriter();
                    p2.PutID(CCommon.MT_GAME_CLIENT_JOIN);
                    p2.PutInt(o.GetClientIndex());
                    p2.PutInt(o.AvatarId);
                    p2.PutInt(o.Chair);
                    p2.PutInt(IsOwner);
                    p2.PutInt(IsViewer);
                    p2.PutInt(o.Level);
                    p2.PutDouble(o.GetGold());
                    p2.PutString(o.Username, CCommon.MAX_USERNAME_LENGTH);
                    p2.PutInt(o.IsChickenBet ? 1 : 0);
                    p2.PutString(o.RealName, CCommon.MAX_USERNAME_LENGTH);
                    p2.PutLengthAndFlip();
                    Client.Send(p2);
                }
            }
        }
    }

    // Send Client Left
    public void SendClientLeft(CClient Client, boolean IsDisconnect)
    {
        CPacketWriter p = new CPacketWriter();
        p.PutID(CCommon.MT_GAME_CLIENT_LEFT);
        p.PutInt(Client.GetClientIndex());
        p.PutLengthAndFlip();
        if (IsPlaying() && CConfig.EnableRobot)
        {
            Client.Send(p);
        } else
        {
            if (IsDisconnect)
            {
                SendExcept(p, Client.GetClientIndex());
            } else
            {
                SendAll(p);
            }
        }
    }

    // Get Bot
    public CClient GetBot()
    {
        for (int i = 0; i < MaxClient; i++)
        {
            if (ClientList[i] != null && ClientList[i].IsBot)
            {
                return ClientList[i];
            }
        }

        return null;
    }

    // Get Next Client
    public CClient GetNextClient(CClient Client)
    {
        int Chair = Client.Chair;
        for (int i = 0; i < MaxClient - 1; i++)
        {
            Chair++;
            if (Chair >= MaxClient)
            {
                Chair = 0;
            }
            if (ClientList[Chair] != null && !ClientList[Chair].IsViewer)
            {
                return ClientList[Chair];
            }
        }

        return null;
    }

    // Get Preview Client
    public CClient GetPrevClient(CClient Client)
    {
        int Chair = Client.Chair;
        for (int i = 0; i < MaxClient - 1; i++)
        {
            Chair--;
            if (Chair < 0)
            {
                Chair = MaxClient - 1;
            }
            if (ClientList[Chair] != null && !ClientList[Chair].IsViewer)
            {
                return ClientList[Chair];
            }
        }

        return null;
    }

    public CChannel GetChannel()
    {
        return Channel;
    }

    public int GetAppID()
    {
        return GetChannel().GetAppID();
    }

    public CGameLogic GetGameLogic()
    {
        return GameLogic;
    }

    public void SetGameLogic(CGameLogic Logic)
    {
        GameLogic = Logic;
    }

    // Set Game Stage
    public void SetGameStage(int GameStage, int TimeStage)
    {
        // Join Viewer
        if (GameStage == CCommon.GS_WAITING_ROOM)
        {
            for (int i = 0; i < MaxClient; i++)
            {
                CClient Client = ClientList[i];
                if (Client != null && Client.IsViewer)
                {
                    Client.IsViewer = false;
                    SendClientJoin(Client);
                }
            }
        }

        // Set Stage
        this.GameStage = GameStage;
        this.TimeStage = TimeStage;
        CPacketWriter Packet = new CPacketWriter();
        Packet.PutID(CCommon.MT_SET_GAME_STAGE);
        Packet.PutInt(GameStage);

        // REMOVE
        if (GetAppID() == 1)
        {
            Packet.PutInt(TimeStage * 1000);
        } else
        {
            Packet.PutInt(TimeStage);
        }
        Packet.PutLengthAndFlip();
        SendAll(Packet);
    }

    // Check Playing
    public boolean IsPlaying()
    {
        return (GameStage != CCommon.GS_WAITING_ROOM && GameStage != CCommon.GS_RESULT);
    }

    // Kick Poor Client
    public void KickPoorClient()
    {
        for (int i = 0; i < MaxClient; i++)
        {
            CClient Client = ClientList[i];
            if (Client != null && !Client.IsViewer)
            {
                if (Client.GetGold() < GoldBet * CConfig.MinToPlay)
                {
                    if (Client.IsBot)
                    {
                        CGlobal.AppContainer.RemoveBot(Client);
                    } else
                    {
                        // Send Notify
                        Client.GetTable().SendClientLeft(Client, false);

                        // Remove Client
                        Client.GetTable().RemoveClient(Client);
                        Client.LeftTable();

                        // Send Lobby Info
                        CBinhHandler.Instance().SendLobbyInfo(Client);

                        // Send Notify Kick
                        // 1 : Owner kick
                        // 2 : Not enough money
                        CPacketWriter p2 = new CPacketWriter();
                        p2.PutID(CCommon.MT_KICK);
                        p2.PutInt(Client.GetClientIndex());
                        p2.PutInt(2);
                        p2.PutLengthAndFlip();
                        Client.Send(p2);
                    }
                }
            }
        }
    }

    // Get Client by Id
    public CClient GetClient(int ClientId)
    {
        for (int i = 0; i < MaxClient; i++)
        {
            if (ClientList[i] != null && ClientList[i].GetClientIndex() == ClientId)
            {
                return ClientList[i];
            }
        }

        return null;
    }

    // Get Player Count in Table
    public int GetNumPlayer()
    {
        int Count = 0;
        for (int i = 0; i < MaxClient; i++)
        {
            if (ClientList[i] != null && ClientList[i].IsLogin() && !ClientList[i].IsViewer)
            {
                Count++;
            }
        }

        return Count;
    }

    // Get Client Count in Table
    public int GetNumClient()
    {
        int Count = 0;
        for (int i = 0; i < MaxClient; i++)
        {
            if (ClientList[i] != null && ClientList[i].IsLogin())
            {
                Count++;
            }
        }

        return Count;
    }

    // Get Real Client Count in Table
    public int GetRealCount()
    {
        int Count = 0;
        for (int i = 0; i < MaxClient; i++)
        {
            if (ClientList[i] != null && ClientList[i].IsLogin() && !ClientList[i].IsBot && !ClientList[i].IsViewer)
            {
                Count++;
            }
        }

        return Count;
    }

    @Override
    public void OnTimer(int delta)
    {
        if (GameStage == CCommon.GS_WAITING_ROOM)
        {
            if (TimeStage > 0)
            {
                TimeStage--;
                if (TimeStage == 0)
                {
                    if (Owner != null && GetNumPlayer() > 1)
                    {
                        // Bot sau 5s tự động start game
                        if (Owner.IsBot)
                        {
                            if (GameLogic != null)
                            {
                                GameLogic.StartGame();
                            }
                        } // Sau 10 không start, chuyển key cho thằng khác
                        else
                        {
                            CClient Next = GetNextClient(Owner);
                            if (Next != null)
                            {
                                SetOwner(Next);
                                CPacketWriter p = new CPacketWriter();
                                p.PutID(CCommon.MT_SET_HOST);
                                p.PutInt(Next.GetClientIndex());
                                p.PutLengthAndFlip();
                                SendAll(p);
                            }
                            TimeStage = CCommon.MAX_TIME_CHANGE_KEY;
                        }
                    }
                }
            }
        }

        if (GameLogic != null)
        {
            GameLogic.OnTimer(delta);
        }
    }

    public boolean CanChangeBet(CClient Client, double NewGoldBet)
    {
        // Số tiền vượt quá mức cho phép
        if (NewGoldBet < Channel.MinGoldBet || NewGoldBet > Channel.MaxGoldBet)
        {
            return false;
        }

        // Số tiền phải lớn hơn 5 lần mức cược
        for (int i = 0; i < MaxClient; i++)
        {
            if (ClientList[i] != null && ClientList[i].IsLogin() && !ClientList[i].IsViewer)
            {
                if (ClientList[i].GetGold() < NewGoldBet * CConfig.MinToPlay)
                {
                    return false;
                }
            }
        }

        return true;
    }

    public double GetAvaiTotalGold(CClient Winner, double TotalGold)
    {
        double Total = 0;
        for (int i = 0; i < MaxClient; i++)
        {
            if (ClientList[i] != null && ClientList[i].IsLogin()
                    && !ClientList[i].IsViewer && ClientList[i].GetClientIndex() != Winner.GetClientIndex())
            {
                Total += ClientList[i].GetGold();
            }
        }
        if (Total < TotalGold)
        {
            return Total;
        }

        return TotalGold;
    }
}